home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2888 / 2888.xpi / components / nsIGMarksService.js < prev    next >
Text File  |  2008-07-22  |  46KB  |  1,345 lines

  1. var GMARKS_CONTRACTID = '@mozilla.org/gmarks;1';
  2. var GMARKS_CID = Components.ID('{47eddc3e-b79f-11db-8314-0800200c9a66}');
  3. var GMARKS_IID = Components.interfaces.nsIGMarksService;
  4.  
  5. var gGMarks;
  6.  
  7. function nsGMarksService() {
  8.   //Who needs interfaces anyway
  9.   this.wrappedJSObject = this;
  10.   this.strbundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService)
  11.     .createBundle("chrome://gmarks/locale/gmarks.properties");
  12.   this.loadPrefs();
  13.   gGMarks=this;
  14.   try{
  15.     var combundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService)
  16.       .createBundle("chrome://gmarks/locale/com.properties");
  17.     this.mode=combundle.GetStringFromName("identifier");
  18.   } catch(e){
  19.     this.mode="google";
  20.   }
  21.   this.com=Components.classes["@mozilla.org/gmarks/com/"+this.mode+";1"]
  22.     .getService(Components.interfaces.nsIGMarksCom).wrappedJSObject
  23.   this.com.setGMS(this);
  24.   this.getBookmarksFeed("onload",false);
  25. }
  26. nsGMarksService.prototype = {
  27.   com: null,
  28.   bookmarkArray: new Array(),
  29.   labelArray: new Array(),
  30.   //the last 10 bookmarks added
  31.   recent: new Array(),
  32.   //10 most frequently visited bookmarks.
  33.   frequent: new Array(),
  34.   searchArray: null,
  35.   recievedBookmarks: 0,
  36.   isSignedIn: false,
  37.   showIcons: true,
  38.   showFavs: true,
  39.   sortBy: 'title',
  40.   qsKey: "",
  41.   qsKeyCode: 36,
  42.   hidden: "",
  43.   unlabeled: "",
  44.   readerLabel: "Google Reader",
  45.   _tabGroup: null,
  46.   validateFavs: false,
  47.   toolbarFolder: null,
  48.   toolbarShowIconsOnly: false,
  49.   signingIn: false,
  50.   loading: false,
  51.   actionHist: new Array(),
  52.   get manageOnlineURL(){
  53.     return this.com.manageOnlineURL;
  54.   },
  55.   loadPrefs: function(){
  56.     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  57.       getService(Components.interfaces.nsIPrefService).getBranch("gmarks");
  58.     this.showIcons=prefs.getBoolPref('.showIcons');
  59.     this.showFavs=prefs.getBoolPref('.showFav');
  60.     if (!this.showIcons){
  61.       this.showFavs=false;
  62.     }
  63.     this.sortBy=prefs.getCharPref('sortby');
  64.     try{
  65.       var t=prefs.getCharPref('.keys.quicksearch.key');
  66.       prefs.clearUserPref('.keys.quicksearch.key');
  67.     }
  68.     catch(e){}
  69.     this.qsKeyCode=prefs.getIntPref('.keys.quicksearch.key');
  70.     this.hidden=prefs.getComplexValue(".hiddenLabels",
  71.       Components.interfaces.nsISupportsString).data;
  72.     this.hidden=this.hidden.split(/\s*,\s*/);
  73.     this.unlabeled=prefs.getComplexValue(".unlabeled",
  74.       Components.interfaces.nsISupportsString).data;
  75.     this.readerLabel=prefs.getCharPref('.readerLabel');
  76.     this.validateFavs=prefs.getBoolPref(".icons.validate");
  77.     try{
  78.       this.toolbarFolder=prefs.getComplexValue(".toolbarFolder",
  79.         Components.interfaces.nsISupportsString).data;
  80.     }
  81.     catch(e){
  82.       this.toolbarFolder=prefs.getCharPref(".toolbarFolder");
  83.     }
  84.     this.toolbarShowIconsOnly=prefs.getBoolPref(".toolbarShowIconsOnly");
  85.     this.nestedChar=prefs.getCharPref(".nestedChar");
  86.     this.showCount=prefs.getBoolPref('.showCount');
  87.     this.confirmDelete=prefs.getBoolPref(".confirmDelete");
  88.     this.showRecent=prefs.getBoolPref(".showRecent");
  89.     this.showFreq=prefs.getBoolPref(".showFreq");
  90.     this.searchType=prefs.getIntPref(".search");
  91.   },
  92.   /* The url the passwords are saved to in Firefox's password manager. With GMarks, its chrome://gmarks */
  93.   getPassLoc : function(){
  94.     return this.com.passLoc;
  95.   },
  96.   /*
  97.    * Adds bookmarks to a queue to be submitted to Google
  98.    */
  99.   set tabGroup(bkmks){
  100.     this._tabGroup=new Array();
  101.     for (var n=0;n<bkmks.length;n++){
  102.       var bm=this.createNewBookmark();
  103.       for (var obj in bkmks[n]){
  104.         bm[obj]=bkmks[n][obj];
  105.       }
  106.       bm.labels=new Array();
  107.       for (var j=0;j<bkmks[n].labels.length;j++)
  108.         bm.labels.push(bkmks[n].labels[j]);
  109.       var idx=this.updateBookmark(bm,n==(bkmks.length-1));
  110.       this._tabGroup.push(bm);
  111.     }
  112.     this.updateMultipleBookmarks(this._tabGroup,0);
  113.   },
  114.   /*
  115.    * Used to undo actions...
  116.    * type=label or bookmark
  117.    * label actions=rename,delete,deletebkmks
  118.    * bkmk  actions=delete,properties [change], add
  119.    */
  120.   generateBkmkAction: function(aType,aAction,aObj1,aObj2){
  121.     var newaction={
  122.       type: aType, action: aAction,
  123.       obj1: aObj1, obj2: aObj2
  124.     };
  125.     this.actionHist.push(newaction);
  126.     //dump("Action added, type="+aType+" action="+aAction+"\n");
  127.     return newaction;
  128.   },
  129.   undoLastAction: function(stopRefresh){
  130.     //dump("History Depth: "+this.actionHist.length+"\n");
  131.     var histaction=this.actionHist.pop();
  132.     if (!histaction) return;
  133.     var type=histaction.type,action=histaction.action;
  134.     //dump("Undo Action: "+type+"|"+action+"\n");
  135.     /*
  136.      * Hopefully these references to removed bkmks stay in tact
  137.      */
  138.     if (type=="label"){
  139.       if (action=="rename"){
  140.         var children=histaction.obj1;
  141.         var bkmks=new Array();
  142.         children.forEach(function(child){
  143.           var oldlbl=child.oldlbl;
  144.           var newlbl=child.newlbl;
  145.           var bkmk  =child.bkmk;
  146.           var idx=bkmk.labels.indexOf(newlbl);
  147.           if (idx>-1)
  148.             bkmk.labels[idx]=oldlbl;
  149.           bkmks.push(bkmk);
  150.         });
  151.         this.updateMultipleBookmarks(bkmks,0);
  152.       }
  153.       else if (action=="add"){
  154.         var bkmks=histaction.obj1;
  155.         var lbl=histaction.obj2;
  156.         bkmks.forEach(function(bkmk){
  157.           /* remove label from bookmark */
  158.           var idx=bkmk.labels.indexOf(lbl);
  159.           if(idx>-1)
  160.             bkmk.labels.splice(idx,1);
  161.         });
  162.         this.updateMultipleBookmarks(bkmks,0);
  163.       }
  164.       else if (action=="delete"){
  165.         var children=histaction.obj1;
  166.         var bkmks=new Array();
  167.         children.forEach(function(child){
  168.           child.bkmk.labels.push(child.label);
  169.           bkmks.push(child.bkmk);
  170.         });
  171.         this.updateMultipleBookmarks(bkmks,0);
  172.       }
  173.       else if (action=="deletebkmks"){
  174.         var bkmks=histaction.obj1;
  175.         bkmks.forEach(function(bkmk){
  176.           this.addBookmark(bkmk);
  177.         },this);
  178.         this.updateMultipleBookmarks(bkmks,0);
  179.       }
  180.     }
  181.     else if (type=="bookmark"){
  182.       if (action=="delete"){/* Add it back */
  183.         var deleted=histaction.obj1;
  184.         this.addBookmark(deleted);
  185.         this.sendUpdateBookmark(deleted,true);
  186.       }
  187.       else if (action=="add"){
  188.         var bkmk=histaction.obj1;
  189.         /* Remove from lists */
  190.         this.removeBookmark(bkmk);
  191.         /* Removes the bookmark from the online service */
  192.         this.com.onRemoveBookmark(bkmk);
  193.       }
  194.       else if (action=="properties"){
  195.         var bkmk=histaction.obj1;
  196.         var changes=histaction.obj2;
  197.         this.removeBookmark(bkmk);
  198.         changes.forEach(function(change){
  199.           //dump("change: "+change.type+"\n");
  200.           if (change.type=="url" && bkmk.url!=change.url){
  201.             this.com.onRemoveBookmark(bkmk);
  202.             bkmk.url=change.url;
  203.             bkmk.id=0;
  204.           }
  205.           else if (change.type=="add label"){
  206.             var lbl=change.label;
  207.             /* remove label from bookmark */
  208.             var idx=bkmk.labels.indexOf(lbl);
  209.             if(idx>-1)
  210.               bkmk.labels.splice(idx,1);
  211.           }
  212.           else if (change.type=="remove label"){
  213.             var lbl=change.label;
  214.             /* add label to bookmark */
  215.             var idx=bkmk.labels.indexOf(lbl);
  216.             if (idx<0)
  217.               bkmk.labels.push(lbl);
  218.           }
  219.           else if (change.type=="title")
  220.             bkmk.title=change.title;
  221.           else if (change.type=="labels"){
  222.             bkmk.labels=change.labels.split(',');}
  223.           else if (change.type=="notes")
  224.             bkmk.notes=change.notes;
  225.         },this);
  226.         this.addBookmark(bkmk);
  227.         this.sendUpdateBookmark(bkmk,true);
  228.       }
  229.     }
  230.     else if (type=="all"){
  231.       if (action=="complex action"){
  232.         histaction.obj1.forEach(function(item){
  233.           this.actionHist.push(item);
  234.           this.undoLastAction(true);
  235.         },this);
  236.       }
  237.     }
  238.     //dump("Action undoifying complete\ntype="+type+" | action="+action+"\nobj1="+histaction.obj1+"\nobj2="+histaction.obj2+"\n");
  239.     if (!stopRefresh)
  240.       this.doCommand("quickrefresh");
  241.   },
  242.   /*
  243.    * Removes a bookmark from Google, if checkConfirm is true and the users preference to confirm on delete is true, it prompts them before deleting
  244.    * bm can be either the url, the index, or the bookmark
  245.    * star is the state of thee GMarks star, "on" and "off" If the current url is being removed, the star should change back to clear.
  246.    *
  247.    * onRemoveBookmark also removes the bookmark from the local bookmarkArray
  248.    */
  249.   onRemoveBookmark : function(bm,refresh,checkConfirm) {
  250.     //dump("onRemoveBookmark: "+bm+"\n");
  251.     if (checkConfirm && this.confirmDelete){
  252.       var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  253.             .getService(Components.interfaces.nsIPromptService);
  254.       var result= prompts.confirm(null, "",
  255.         this.strbundle.GetStringFromName("removeBookmark")+' "'+bm.title+'"');
  256.       if (!result){
  257.         return;
  258.       }
  259.     }
  260.     /*
  261.      * Checks to see if its the current url, if so, it needs to change the star from bookmarked to not bookmarked
  262.      */
  263.     var topWindowOfType = this.getBrowserWindow();
  264.     /*
  265.     if (topWindowOfType) {
  266.       var url=null;
  267.       if (typeof bm=='string')
  268.         url=bm;
  269.       else if (typeof bm!='number')
  270.         url=bm.url;
  271.       if (url==topWindowOfType.content.location.href){
  272.         star=star?star:"off";
  273.         Components.classes["@mozilla.org/observer-service;1"]
  274.          .getService(Components.interfaces.nsIObserverService)
  275.          .notifyObservers(null, "star-change", star);
  276.       }
  277.     }
  278.     */
  279.     var idx;
  280.     if (typeof bm=='string')
  281.       idx=this.isBookmarked(bm);
  282.     else if (typeof bm=='number')
  283.       idx=bm;
  284.     else{
  285.       idx=this.isBookmarked(bm.url);
  286.     }
  287.     var bkmk=this.bookmarkArray[idx];
  288.     //dump("remove bookmark at "+idx+" with url: "+bkmk.url+"\n");
  289.     /* Create a bookmark action so it can be undone */
  290.     this.generateBkmkAction("bookmark","delete",bkmk);
  291.     /* Remove from lists */
  292.     var id=this.removeBookmark(idx,refresh);
  293.     /* Removes the bookmark from the online service */
  294.     this.com.onRemoveBookmark(bkmk);
  295.   },
  296.   /*
  297.    * Renames oldLabel to newLabel, modifies the label in the bookmarkArray and online
  298.    * If there is no new label, it removes the old label
  299.    */
  300.   onRenameLabel: function(oldLabel, newLabel,refresh){
  301.   if (!newLabel || newLabel=="") {this.onRemoveLabel(oldLabel,true,true); return;}
  302.     var children=new Array();
  303.     for (i=0; i < this.bookmarkArray.length; i++){
  304.       for (j=0; j < this.bookmarkArray[i].labels.length; j++) {
  305.         if (this.bookmarkArray[i].labels[j] == oldLabel){
  306.           children.push({bkmk: this.bookmarkArray[i],oldlbl: oldLabel, newlbl: newLabel});
  307.           this.bookmarkArray[i].labels[j] = newLabel; break;
  308.         }
  309.       }
  310.     }
  311.     /* Create a bookmark action so it can be undone */
  312.     this.generateBkmkAction("label","rename", children);
  313.  
  314.     this.com.onRenameLabel(oldLabel,newLabel);
  315.     if (refresh) this.doCommand("quickrefresh");
  316.   },
  317.   /*
  318.    * Removes the label locally and online, does not delete the bookmarks belonging to the label
  319.    */
  320.   onRemoveLabel: function(label,refresh,checkConfirm){
  321.     if (checkConfirm && this.confirmDelete){
  322.       var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  323.             .getService(Components.interfaces.nsIPromptService);
  324.       var result= prompts.confirm(null, "",
  325.         this.strbundle.GetStringFromName("removeLabel")+' "'+label+'"');
  326.       if (!result){
  327.         return;
  328.       }
  329.     }
  330.     var children=new Array();
  331.     for (i=0; i < this.bookmarkArray.length; i++)
  332.       for (j=0; j < this.bookmarkArray[i].labels.length; j++)
  333.         if (this.bookmarkArray[i].labels[j] == label){
  334.           children.push(this.bookmarkArray[i]);
  335.           this.bookmarkArray[i].labels.splice(j,1);
  336.         }
  337.  
  338.     /* Create a bookmark action so it can be undone */
  339.     this.generateBkmkAction("label","delete", children,label);
  340.  
  341.     this.com.onRemoveLabel(label);
  342.     if (refresh) this.doCommand("quickrefresh");
  343.   },
  344.   /*
  345.    * Adds a label to the bookmark, if no label exists it prompts the user for a label
  346.    * bm can be a url or a bookmark object
  347.    *
  348.    * updates the bookmark locally and online
  349.    */
  350.   addLabelToBookmark: function(bm,label,refresh){
  351.     if (label==null || label.length==0){
  352.       var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  353.             .getService(Components.interfaces.nsIPromptService);
  354.       var input = {value: ""};
  355.       var checked = {value: false};
  356.       var result = prompts.prompt(null, "",
  357.           this.strbundle.GetStringFromName('addLabelToBookmarkPrompt'),
  358.           input,null,checked);
  359.       label=input.value;
  360.       if (!result || label==null || label.length==0)
  361.         return;
  362.     }
  363.     if (typeof bm=='string') //string==its a url
  364.       bm=this.getBookmark(bm);
  365.  
  366.     if (this.hasLabel(bm.labels,label)) return;//No point in adding a duplicate label...
  367.     var labels=label.split(/,\s*/);
  368.     for (var i=0;i<labels.length;i++){
  369.       labels[i]=labels[i].replace(/^\s*|\s*$/g,"");
  370.       if (labels[i].length==0 || labels[i]==" " || labels[i].match(/^\s+$/))
  371.         labels.splice(i,1);
  372.     }
  373.     bm.labels=bm.labels.concat(labels);//Add label
  374.     this.updateBookmark(bm,refresh);
  375.  
  376.     /* Create a bookmark action so it can be undone */
  377.     var obj2=new Array();
  378.     for (var i=0;i<labels.length;i++)
  379.       obj2.push({type: "add label",label: labels[i]});
  380.     this.generateBkmkAction("bookmark","properties", bm,obj2);
  381.  
  382.     this.com.onAddLabelsToBookmark(bm,labels);
  383.   },
  384.   /*
  385.    * Removes the label from the bookmark
  386.    * bm can be either a url or a bookmark object
  387.    *
  388.    * updates the bookmark locally and online...
  389.    */
  390.   removeLabelFromBookmark: function(bm,label,refresh){
  391.     if (typeof bm=='string')
  392.       bm=this.getBookmark(bm);
  393.  
  394.     var newLabels=new Array();
  395.  
  396.     for (var i=0;i<bm.labels.length;i++){
  397.       if (bm.labels[i] != label)
  398.         newLabels.push(bm.labels[i]);
  399.     }
  400.     bm.labels=newLabels;
  401.     this.updateBookmark(bm,refresh);
  402.  
  403.     /* Create a bookmark action so it can be undone */
  404.     this.generateBkmkAction("bookmark","properties", bm,[{type: "remove label",label: label}]);
  405.  
  406.     this.com.onRemoveLabelFromBookmark(bm,label);
  407.   },
  408.   /*
  409.    * Renames the bookmark, prompts the user if necessary
  410.    * bm == url || bookmark objec
  411.    *
  412.    * updates the bookmark locally and online
  413.    */
  414.   onRenameBookmark: function(bm,title,refresh){
  415.     if (typeof bm=='string')
  416.       bm=this.getBookmark(bm);
  417.     if (title==null || title.length==0){
  418.       var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  419.             .getService(Components.interfaces.nsIPromptService);
  420.       var input = {value: bm.title};
  421.       var checked = {value: false};
  422.       var result= prompts.prompt(null, "",
  423.         this.strbundle.GetStringFromName("renameBookmark"), input,null,checked);
  424.       title=input.value;
  425.       if (!result || title==null || title.length==0)
  426.         return;
  427.     }
  428.     if (title){
  429.       //id, url, title, labels, notes, date, image
  430.       var old=this.createNewBookmark(bm.id, bm.url, bm.title,bm.labels, bm.notes,
  431.           bm.date,bm.image);
  432.       this.removeBookmark(old);
  433.  
  434.       /* Create a bookmark action so it can be undone */
  435.       var obj=new Array({type: "title",title: bm.title});
  436.       this.generateBkmkAction("bookmark","properties", bm,obj);
  437.  
  438.       bm.title=title;
  439.       this.updateBookmark(bm,refresh);
  440.  
  441.       this.com.onRenameBookmark(bm,title);
  442.     }
  443.   },
  444.   sendUpdateBookmark: function(bm,async){
  445.     this.com.sendUpdateBookmark(bm,async);
  446.   },
  447.   errorSendingBookmark: function(bm){
  448.     var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  449.           .getService(Components.interfaces.nsIPromptService);
  450.     var result= prompts.alert(this.getBrowserWindow(), "",
  451.       this.strbundle.GetStringFromName("submissonError")+"\n"+
  452.       bm.title+"\n"+bm.url);
  453.   },
  454.   /*
  455.    * Updates a group of bookmarks one at a time, sending too many bookmarks at a time causes the requests to be lost
  456.    */
  457.   updateMultipleBookmarks: function(bkmks,i){
  458.     if (i==null){
  459.       for (var n=0;n<bkmks.length;n++){
  460.         this.updateBookmark(bkmks[n],n==(bkmks.length-1));
  461.       }
  462.       i=0;
  463.     }
  464.     this.com.updateMultipleBookmarks(bkmks,i);
  465.   },
  466.   /*
  467.    * Returns a new bookmark object with the current date and the passed in properties
  468.    */
  469.   createNewBookmark: function(aId, aURL, aTitle, aLabels, aNotes, aDate, aImage,
  470.       aService, aMode,aFreq){//aId, aURL, aTitle, aLabels, aNotes, aDate, aImage
  471.     if (aDate==null){
  472.       var d=new Date();
  473.       aDate=d;
  474.       //aDate=d.valueOf()*1000+d.getMilliseconds();
  475.     }
  476.     if (aLabels && typeof aLabels=="string") aLabels=[aLabels];
  477.     aService=aService?aService:"bookmarks";
  478.     if (this.mode=="simpy")
  479.       aMode=aMode?aMode:this.com.visibility;
  480.     else
  481.       aMode=0;
  482.     return {
  483.       id: aId, url: aURL, title: aTitle, pageTitle: aTitle, mode: aMode,
  484.       labels: aLabels?aLabels:new Array(), notes: aNotes?aNotes:"",
  485.       date: aDate, image: aImage, serv: aService, freq: aFreq
  486.     };
  487.     /*
  488.     toString: function(){
  489.         return 'id='+id +'&url='+url+ '&title='+title+'&labels='+labels+ '¬es='+notes;
  490.      */
  491.   },
  492.   getPassInfo: function(){
  493.     var hostString = this.getPassLoc();//'chrome://gmarks';
  494.     //FF2
  495.     if (Components.classes["@mozilla.org/passwordmanager;1"]){
  496.       var passwordManager = Components.classes["@mozilla.org/passwordmanager;1"]
  497.                     .getService(Components.interfaces.nsIPasswordManager);
  498.       var e = passwordManager.enumerator;
  499.       while (e.hasMoreElements()) {
  500.         try {
  501.           // get an nsIPassword object out of the password manager.
  502.           // This contains the actual password...
  503.           var pass = e.getNext().QueryInterface(Components.interfaces.nsIPassword);
  504.           if (pass.host == hostString) {
  505.              // found it!
  506.              return pass;
  507.           }
  508.         } catch (ex) {//Decrypting Failed
  509.           continue;
  510.         }
  511.       }
  512.     }
  513.     else if (Components.classes["@mozilla.org/login-manager;1"]){
  514.       var formSubmitURL = '/';
  515.       var httprealm = null;
  516.       var password;
  517.  
  518.       try {
  519.          // Get Login Manager
  520.          var passwordManager = Components.classes["@mozilla.org/login-manager;1"]
  521.           .getService(Components.interfaces.nsILoginManager);
  522.          // Find users for the given parameters
  523.          var logins = passwordManager.findLogins({}, hostString, formSubmitURL, httprealm);
  524.          if (logins.length>0)
  525.           return {user: logins[0].username, password: logins[0].password};
  526.       }
  527.       catch(ex) {
  528.          // This will only happen if there is no nsILoginManager component class
  529.       }
  530.     }
  531.     return {user: null, password: null};
  532.   },
  533.   savePassInfo: function(user,password){
  534.     if (Components.classes["@mozilla.org/passwordmanager;1"]){
  535.       var passwordManager = Components.classes["@mozilla.org/passwordmanager;1"]
  536.           .getService(Components.interfaces.nsIPasswordManager);
  537.        try{
  538.         var pass=this.getPassInfo();
  539.         while (pass!=null && (pass.user!=user || pass.password!=password)){
  540.           passwordManager.removeUser(this.getPassLoc(),pass.user);
  541.           pass=this.getPassInfo();
  542.         }
  543.       }
  544.       catch(e){}
  545.       if (user && user.length>0)
  546.         passwordManager.addUser(this.getPassLoc(), user, password);
  547.     }
  548.     else if (Components.classes["@mozilla.org/login-manager;1"]){//FF3
  549.       var passwordManager = Components.classes["@mozilla.org/login-manager;1"]
  550.         .getService(Components.interfaces.nsILoginManager);
  551.       var hostString = this.getPassLoc();
  552.       var formSubmitURL = '/';
  553.       var httprealm = null;
  554.       var logins = passwordManager.findLogins({}, hostString, formSubmitURL, httprealm);
  555.       var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
  556.         Components.interfaces.nsILoginInfo);
  557.       var extLoginInfo = new nsLoginInfo();
  558.       extLoginInfo.init(this.getPassLoc(), '/', null, user, password, '', '');
  559.       if (logins.length==0){
  560.         if (user && user.length>0)
  561.           passwordManager.addLogin(extLoginInfo);
  562.       }
  563.       else if (user && user.length>0)
  564.         passwordManager.modifyLogin(logins[0],extLoginInfo);
  565.       else
  566.         passwordManager.removeLogin(logins[0]);
  567.       }
  568.   },
  569.   /*
  570.    * Checks to see if you are signed in or not
  571.    */
  572.   checkSignedCookie: function(){
  573.     return this.com.checkSignedCookie();
  574.   },
  575.   /*
  576.    * Signs in
  577.    */
  578.   onSignIn: function(refresh,email,pass,action,sidebar,start,num) {
  579.     this.com.onSignIn(refresh,email,pass,action,sidebar,start,num);
  580.   },
  581.   signOut: function(){
  582.     this.bookmarkArray=new Array();
  583.     this.searchArray=new Array();
  584.     this.recent=new Array();
  585.     this.frequent=new Array();
  586.     this.isSignedIn=false;
  587.     this.loading=false;
  588.     this.isSignedIn=false;
  589.     this.recievedBookmarks=0;
  590.     this.com.signOut();
  591.     this.doCommand("quickrefresh");
  592.   },
  593.   /*
  594.    * Downloads the bookmark xml feed and calls the command passed in (action)
  595.    * There are so many try and catches because I got fed up with people complaining of all these obscure errors.
  596.    */
  597.   getBookmarksFeed: function(action,sidebar,start,num){
  598.     this.doCommand("bookmarks-load-start");
  599.     this.actionHist=new Array();
  600.     this.com.getBookmarksFeed(action,sidebar,start,num);
  601.   },
  602.   /*
  603.    * Same as the getBookmarksFeed, but returns only those which fit the query
  604.    */
  605.   getSiteSearch: function(query, action, sidebar){
  606.     if (this.searchType==0)
  607.       this.com.getSiteSearch(query,action,sidebar);
  608.     else{
  609.       this.searchArray = this.getMatchingBookmarks(query);
  610.       this.doCommand(action);
  611.     }
  612.   },
  613.   /*
  614.    * Retrieves the starred items from Google Reader
  615.    * This is not called by default, there is an option to turn this on.
  616.    */
  617.   getReaderStars : function(action){
  618.     this.com.getReaderStars(action);
  619.   },
  620.   /*
  621.    * Gets the id of the last added bookmark so it can be removed during the current session.
  622.    */
  623.   getID : function(bm){
  624.     this.com.getId(bm);
  625.   },
  626.   //returns the favicon at domain.tld/favicon.ico of a url
  627.   getIcon : function(bmUrl){
  628.     if (!this.showIcons || !this.showFavs && bmlURL!="about:blank") return null;
  629.     var ioservice = Components.classes["@mozilla.org/network/io-service;1"]
  630.       .getService(Components.interfaces.nsIIOService);
  631.     try{
  632.     var url = ioservice.newURI(bmUrl, null, null);
  633.     var scheme = url.scheme;
  634.     if (url.hostPort && scheme){
  635.       if (scheme=="https") 
  636.         url.scheme = scheme ="http";
  637.       if (scheme=="http")
  638.         return ioservice.newURI(scheme + "://" + url.hostPort + "/favicon.ico", null, null);
  639.     }
  640.     }catch(e){}
  641.     return null;
  642.   },
  643.   //Sets the icon of bookmark, checks if the favicon exists first if validate favicons is enabled
  644.   getImage: function(bkmkIdx,type){
  645.     if (!this.showIcons || !this.showFavs) return;
  646.     type=type==null?0:type;
  647.     var bkmk;
  648.     if (type==0){
  649.       bkmk=this.bookmarkArray[bkmkIdx];
  650.     }
  651.     else{
  652.       bkmk=this.searchArray[bkmkIdx];
  653.     }
  654.     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  655.       getService(Components.interfaces.nsIPrefService).getBranch("gmarks");
  656.     var lookup = prefs.getCharPref(".favicons");
  657.     //Check if its in the notes
  658.     var pos=bkmk.notes.lastIndexOf("data:image");
  659.     if (pos>-1){//Old style
  660.       //Google removes + signs, replaces them with spaces.
  661.       var newImage=bkmk.notes.substring(pos).replace(/\s/g,"+");
  662.       bkmk.image=newImage;
  663.     }
  664.     else if ((pos=bkmk.notes.lastIndexOf("favicon:"))>-1){//New style
  665.       var newImage=bkmk.notes.substring(pos+8);
  666.       bkmk.image=newImage;
  667.     }
  668.     else if (lookup == "gmarks" &&
  669.              Components.classes["@mozilla.org/browser/favicon-service;1"]){//FF3
  670.       try{
  671.       var faviconService = Components.classes["@mozilla.org/browser/favicon-service;1"]
  672.                  .getService(Components.interfaces.nsIFaviconService);
  673.       var ioservice = Components.classes["@mozilla.org/network/io-service;1"]
  674.         .getService(Components.interfaces.nsIIOService);
  675.       var uri = ioservice.newURI(bkmk.url, null, null);
  676.       bkmk.image=faviconService.getFaviconImageForPage(uri).spec;
  677.       }catch(e){
  678.         //dump(e+"\nUrl Error: "+bkmk.url+"\n");
  679.       }
  680.  
  681.     }//FF2
  682.     else if (!this.validateFavs) {
  683.       var icon=this.getIcon(bkmk.url);
  684.       if (icon)
  685.         bkmk.image=icon.spec;
  686.       else
  687.         bkmk.image=null;
  688.     }
  689.     else{
  690.       try{
  691.         if (bkmk.image==null && bkmk.url.substring(0,4)=="http"){
  692.           var img=this.getIcon(bkmk.url);
  693.           if (img!=null){
  694.             var uriChecker = Components.classes["@mozilla.org/network/urichecker;1"].createInstance()
  695.                   .QueryInterface(Components.interfaces.nsIURIChecker);
  696.             uriChecker.init(img);
  697.             uriChecker.asyncCheck(new imageURIChecker(bkmkIdx,type,bkmk.url),img);
  698.           }
  699.         }
  700.       }
  701.       catch(e){
  702.         Components.utils.reportError(e+"\nType: "+type);
  703.       }
  704.     }
  705.   },
  706.   //Gets all the images..
  707.   getImages : function(searching){
  708.     //dump("get images1\n");
  709.     if (!this.showIcons || !this.showFavs || !this.validateFavs) return;
  710.     //dump("get images2\n");
  711.     var bkmks=!searching?GMS.bookmarkArray:GMS.searchArray;
  712.     this.favResponses=0;
  713.     for (var i=0;i<bkmks.length;i++){
  714.       this.getImage(bkmks[i],(searching==true?1:0));
  715.     }
  716.     //dump("redraw images\n");
  717.     this.doCommand("redrawImages");
  718.   },
  719.  
  720.  
  721.   connectionError: function(bm){
  722.     debug("connection error\n");
  723.     if (bm!=null)
  724.       this.doCommand("connectionerror",bm.url+"|"+bm.title);
  725.   },
  726.   //Shouldnt be in here...I put it in here and the xpt when testing how to make an XPCOM component
  727.   reverseIt: function(s) {
  728.     var a = s.split("");
  729.     a = a.reverse();
  730.     return a.join("");
  731.   },
  732.   //Sends the commands to the sidebar and toolbar, or whatever else is observing the commands
  733.   doCommand: function(command,data){
  734.     //if (command=="quickfresh")
  735.     //dump("doCommand: gmarks-"+command+"\n");
  736.     if (command!=null)
  737.       Components.classes["@mozilla.org/observer-service;1"]
  738.          .getService(Components.interfaces.nsIObserverService)
  739.          .notifyObservers(null, "gmarks-"+command, data);
  740.  
  741.   },
  742.   removeFromRecent: function(bkmk){
  743.     if (this.recent.length>0)
  744.       if (bkmk.date>this.recent[this.recent.length-1].date){
  745.         var j;
  746.         for (j=this.recent.length-1;j>=0 && bkmk.date>=this.recent[j].date;j--){
  747.           if (bkmk.url==this.recent[j].url){
  748.             this.recent.splice(j,1);
  749.             return true;
  750.           }
  751.         }
  752.       }
  753.     return false;
  754.   },
  755.   removeFromFrequent: function(bkmk){
  756.     if (this.frequent.length>0)
  757.       if (bkmk.freq>this.frequent[this.frequent.length-1].freq){
  758.         var j;
  759.         for (j=this.frequent.length-1;j>=0 && bkmk.freq>=this.frequent[j].freq;j--){
  760.           if (bkmk.url==this.frequent[j].url){
  761.             this.frequent.splice(j,1);
  762.             return true;
  763.           }
  764.         }
  765.       }
  766.     return false;
  767.   },
  768.   updateRecent: function(bkmk){
  769.     var addedbkmk=false;
  770.     if (this.recent.length<10 ||
  771.       (this.recent.length>0 && bkmk.date>
  772.       this.recent[this.recent.length-1].date)){
  773.  
  774.       var currentIndex=-1;
  775.       var moveToIndex=-1;
  776.       for (var j=0;j<this.recent.length;j++){
  777.         if (moveToIndex==-1 && bkmk.date>this.recent[j].date){
  778.           moveToIndex=j;
  779.         }
  780.         if (bkmk.url==this.recent[j].url){
  781.           currentIndex=j;
  782.           break;
  783.         }
  784.       }
  785.       if (moveToIndex!=-1){
  786.         if (currentIndex==-1){
  787.           this.recent.splice(moveToIndex,0,bkmk);
  788.           addedbkmk=true;
  789.         }
  790.         else if (moveToIndex>currentIndex && currentIndex!=-1){
  791.           this.recent.splice(currentIndex,1);
  792.           this.recent.splice(moveToIndex,0,bkmk);
  793.           addedbkmk=true;
  794.         }
  795.       }
  796.       if (this.recent.length<10 && !addedbkmk){
  797.         this.recent.push(bkmk);
  798.         addedbkmk=true;
  799.       }
  800.       if (this.recent.length>10)
  801.         this.recent.splice(10,1);
  802.     }
  803.     return addedbkmk;
  804.   },
  805.   updateFrequent: function(bkmk){
  806.     var addedbkmk=false;
  807.     for (var j=0;j<this.frequent.length;j++){
  808.       if (bkmk.freq>this.frequent[j].freq){
  809.         this.frequent.splice(j,0,bkmk);
  810.         addedbkmk=true;
  811.         break;
  812.       }
  813.     }
  814.     if (this.frequent.length<10 && !addedbkmk && bkmk.freq>0){
  815.       this.frequent.push(bkmk);
  816.       addedbkmk=true;
  817.     }
  818.     if (this.frequent.length>10)
  819.       this.frequent.splice(10,1);
  820.     return addedbkmk;
  821.   },
  822.   /*
  823.    * returns a bookmark object. Index can be either the url or index in the bookmarksArray.
  824.    */
  825.   getBookmark: function(index) {
  826.     if (typeof index=='string'){//if its a url
  827.       index=this.isBookmarked(index);
  828.     }
  829.     if (index && index>=0 && index<this.bookmarkArray.length)
  830.       return this.bookmarkArray[index];
  831.     else
  832.       return null;
  833.   },
  834.   /*
  835.    * sets a bookmark at index in bookmarkArray equal to the passed in bookmark
  836.    */
  837.   setBookmark: function(index, aBookmark) {this.bookmarkArray[index]=aBookmark;},
  838.   /*
  839.    * Removes a bookmark. bkmk can be either the index in bookmarkArray or a url. If refresh is true the quicksearch command is sent to all observers(such as the GMarks sidebar)
  840.    * returns the id of the bookmark removed [The bookmark's id is the only parameter taken by Google in order to delete a bookmark]
  841.    */
  842.   removeBookmark: function(bkmk,refresh){
  843.     var idx=typeof bkmk=='number'?bkmk:this.isBookmarked(bkmk.url);
  844.     if (idx>=0) {
  845.       this.removeFromRecent(this.bookmarkArray[idx]);
  846.       this.removeFromFrequent(this.bookmarkArray[idx]);
  847.       var id=this.bookmarkArray[idx].id;
  848.       var url=this.bookmarkArray[idx].url;
  849.       this.bookmarkArray.splice(idx,1);
  850.       this.doCommand('url-removed',url);
  851.       if (refresh) this.doCommand("quickrefresh");
  852.       return id;
  853.     }
  854.     else
  855.       return null;
  856.   },
  857.   /*
  858.    * Adds a bookmark to the bookmarkArray
  859.    */
  860.    addBookmark: function(bkmk,refresh){
  861.     var idx=this.getBookmarkIndex(bkmk);
  862.     if (idx<0){
  863.       idx=-(idx+1)
  864.       this.bookmarkArray.splice(idx,0,bkmk);
  865.     }
  866.     else if (this.bookmarkArray.length==0 || (idx==0 && this.bookmarkArray[0].url!=bkmk.url)){
  867.       this.bookmarkArray.splice(0,0,bkmk);
  868.     }
  869.     this.updateRecent(bkmk)
  870.     if (!this.loading)
  871.       this.doCommand("url-added",bkmk.url);
  872.     if (refresh) this.doCommand("quickrefresh");
  873.     return idx;
  874.    },
  875.   /*
  876.    * Updates a bookmark's details and updates the date in the bookmarkArray.
  877.    * Does NOT submit an update to Google(or any other site)
  878.    * bkmk is a bookmark object
  879.    *
  880.    * returns the index where the bookmark is
  881.    */
  882.   updateBookmark: function(bkmk,refresh,idx, noimage){
  883.     //var d=new Date();
  884.     if (idx==null){
  885.       idx=this.getBookmarkIndex(bkmk);
  886.     }
  887.     var getNewImage=false;
  888.     if (idx<0){
  889.       idx=-(idx+1)
  890.       this.bookmarkArray.splice(idx,0,bkmk);
  891.       if (!this.loading)
  892.         this.doCommand("url-added",bkmk.url);
  893.       getNewImage=true;
  894.     }
  895.     else if (this.bookmarkArray.length==0 || (idx==0 && this.bookmarkArray[0].url!=bkmk.url)){
  896.       this.bookmarkArray.splice(0,0,bkmk);
  897.       getNewImage=true;
  898.     }
  899.     else{
  900.       if (this.bookmarkArray[idx].url==bkmk.url){
  901.         bkmk.image=this.bookmarkArray[idx].image;
  902.       }
  903.       else
  904.         getNewImage=true;
  905.       this.bookmarkArray[idx]=bkmk;
  906.     }
  907.     this.updateRecent(bkmk);
  908.     if (getNewImage && !noimage)
  909.       this.getImage(idx,0);
  910.     if (refresh) this.doCommand("quickrefresh");
  911.     if (idx>=0)
  912.       return idx;
  913.     else
  914.       return -idx;
  915.   },
  916.   //Searches for the bookmark
  917.   getBookmarkIndex: function(value, a, startPos,endPos){//Binary Search
  918.     a=a?a:this.bookmarkArray;
  919.     startPos=startPos?startPos:0; endPos=endPos?endPos: a.length-1;
  920.     var result=null;
  921.     if (this.sortBy=="title")
  922.       result= this.getTitleIndex(value,a,startPos,endPos);
  923.     else if (this.sortBy=="date")
  924.       result= this.getDateIndex(value,a,startPos,endPos);
  925.     else if (this.sortBy=="freq")
  926.       result= this.getFreqIndex(value,a,startPos,endPos);
  927.     return result;
  928.   },
  929.   findBookmarkByTitle: function(value,a,i){
  930.     var j,k;
  931.     for (var j=i;j<a.length;j++){
  932.       if (value.url==a[j].url){
  933.         //dump("found match("+j+" )"+a[j].url+"\n");
  934.         return j;
  935.       }
  936.       else if (value.title!=a[j].title) break;
  937.     }
  938.     for (var k=i;k>=0;k--){
  939.       if (value.url==a[k].url){
  940.         //dump("found match("+k+" )"+a[k].url+"\n");
  941.         return k;
  942.       }
  943.       else if (value.title!=a[k].title) break;
  944.     }
  945.     return -i;
  946.   },
  947.   GM_dump: function(msg,check){
  948.     check=check?check:msg;
  949.     if (check.indexOf("GMarks")>-1 || true){
  950.       //dump(msg);
  951.     }
  952.   },
  953.   getTitleIndex: function(value,a,low,high){
  954.     if (high==-1) return -1;
  955.     var mid, midVal;
  956.     var title=value.title.toLowerCase();
  957.     while (low <= high) {
  958.       mid = Math.floor(low + ((high - low) / 2));
  959.       midVal=a[mid].title.toLowerCase();
  960.       if (title<midVal)
  961.         high = mid - 1;
  962.       else if (title>midVal)
  963.         low = mid + 1;
  964.       else{
  965.         if (value.url==a[mid].url)
  966.           return mid;
  967.         else
  968.           return this.findBookmarkByTitle(value,a,mid);
  969.       }
  970.     }
  971.     if (title<midVal)
  972.       return -mid-1;
  973.     else
  974.       return -mid-2;
  975.   },
  976.   getDateIndex: function(value,a,low,high){
  977.     if (high==-1) return -1;
  978.     var mid, midVal;
  979.     var date=value.date.getTime();
  980.     while (low <= high) {
  981.       mid = Math.floor(low + ((high - low) / 2));
  982.       midVal=a[mid].date.getTime();
  983.       if (date<midVal)
  984.         high = mid - 1;
  985.       else if (date>midVal)
  986.         low = mid + 1;
  987.       else{
  988.         if (value.url==a[mid].url)
  989.           return mid;
  990.         else
  991.           return this.findBookmarkByTitle(value,a,mid);
  992.       }
  993.     }
  994.     if (date>midVal)
  995.       return -mid-1;
  996.     else
  997.       return -mid-2;
  998.   },
  999.   getFreqIndex: function(value,a,low,high){
  1000.     if (high==-1) return -1;
  1001.     var mid, midVal;
  1002.     var freq=value.freq;
  1003.     while (low <= high) {
  1004.       mid = Math.floor(low + ((high - low) / 2));
  1005.       midVal=a[mid].freq;
  1006.       if (freq>midVal)
  1007.         high = mid - 1;
  1008.       else if (freq<midVal)
  1009.         low = mid + 1;
  1010.       else{
  1011.         if (value.url==a[mid].url)
  1012.           return mid;
  1013.         else
  1014.           return this.findBookmarkByTitle(value,a,mid);
  1015.       }
  1016.     }
  1017.     if (freq>midVal)
  1018.       return -mid-1;
  1019.     else
  1020.       return -mid-2;
  1021.   },
  1022.   queryMatchesBookmark: function(query, bm){
  1023.     var realStart;
  1024.     var urlPos=0;
  1025.     var pChar;
  1026.     if ((realStart=bm.title.toLowerCase().indexOf(query))>-1){
  1027.       if (realStart==0 || bm.title.substring(realStart-1,realStart)==" ")
  1028.         return 0;
  1029.       else
  1030.         return 1;;
  1031.       //break;
  1032.     }
  1033.     if ((urlPos=bm.url.toLowerCase().indexOf(query))==0){
  1034.       return 0;
  1035.     }
  1036.     if ((realStart=bm.url.indexOf("://"))>-1
  1037.         && bm.url.substring(realStart+3,realStart+3+query.length).toLowerCase()==query){
  1038.       return 0;
  1039.     }
  1040.     if (urlPos>0 && (pChar-bm.url.substring(urlPos-1,urlPos))=="." || pChar=="/" || pChar=="-" || pChar=="_" || pChar=="+"){
  1041.       return 0;
  1042.     }
  1043.     if (urlPos>-1){
  1044.       return 2;
  1045.     }
  1046.     if (bm.labels.toString().toLowerCase().indexOf(query)>-1){
  1047.       return 3;
  1048.     }
  1049.     if (bm.notes.toString().toLowerCase().indexOf(query)>-1){
  1050.       return 4;
  1051.     }
  1052.     var qlbls = query.split(/\s*,\s*/);
  1053.     var lbls = bm.labels.toString().toLowerCase().split(/\s*,\s*/);
  1054.     var matchedLbls = true;
  1055.     for (var j = 0;matchedLbls && j<qlbls.length;j++){
  1056.       var qlbl = qlbls[j];
  1057.       matchedLbls = lbls.some(function(item){
  1058.          return item.substring(0,qlbl.length) == qlbl;
  1059.       });
  1060.     }
  1061.     if (matchedLbls){
  1062.       return 3;
  1063.     }
  1064.     return -1;
  1065.   },
  1066.   //Used by the quick search
  1067.   getMatchingBookmarks: function(query, exactQuery){
  1068.     var matching=new Array();
  1069.     var secondMatching=new Array();
  1070.     var url2Matching=new Array();
  1071.     var lblsMatching=new Array();
  1072.     var notesMatching=new Array();
  1073.     var spacesMatching=new Array();
  1074.     var matchLevels = [
  1075.       matching,
  1076.       secondMatching,
  1077.       url2Matching,
  1078.       lblsMatching,
  1079.       notesMatching,
  1080.       spacesMatching
  1081.     ];
  1082.     query=query.toLowerCase();
  1083.     for (var i=0;i<this.bookmarkArray.length;i++){
  1084.       try{
  1085.         var bm=this.bookmarkArray[i];
  1086.         var level = this.queryMatchesBookmark(query,bm);
  1087.         if (!exactQuery && level == -1 ){
  1088.           var words = query.split(/\s+/);
  1089.           var matched = true;
  1090.           for (var j = 0;matched && j<words.length;j++){
  1091.             var word = words[j];
  1092.             level = this.queryMatchesBookmark(word,bm);
  1093.             matched = level != -1;
  1094.           }
  1095.           if (matched)
  1096.             level = matchLevels.length-1;
  1097.           else
  1098.             level = -1;
  1099.         }
  1100.         if (level>-1)
  1101.           matchLevels[level].push(bm);
  1102.       }
  1103.       catch(e){
  1104.         Components.utils.reportError("Bookmark search error:\n"+e);
  1105.       }
  1106.     }
  1107.     matching=matching.concat(secondMatching,url2Matching, lblsMatching, notesMatching, spacesMatching);
  1108.     //matching=matching.concat(lblsMatching);
  1109.     //matching=matching.concat(notesMatching);
  1110.     return matching;
  1111.   },
  1112.   getBookmarkVisits: function(aURL,RDF,HISTDS){
  1113.     if (Components.classes["@mozilla.org/browser/nav-history-service;1"]){//FF3
  1114.       try{
  1115.         var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"]
  1116.                                     .getService(Components.interfaces.nsINavHistoryService);
  1117.        var options = historyService.getNewQueryOptions();
  1118.        var query = historyService.getNewQuery();
  1119.        var ios = Components.classes["@mozilla.org/network/io-service;1"]
  1120.                      .getService(Components.interfaces.nsIIOService);
  1121.        query.uri = ios.newURI(aURL, null, null);
  1122.        var result = historyService.executeQuery(query, options);
  1123.        var cont=result.root;
  1124.        cont.containerOpen = true;
  1125.        if (cont.childCount>0)
  1126.          return cont.getChild(0).accessCount;
  1127.       }
  1128.       catch(e){/* History error/malformed uri */}
  1129.     }
  1130.     else{
  1131.       var kRDFLITIID = Components.interfaces.nsIRDFLiteral;
  1132.       var kRDFINTIID = Components.interfaces.nsIRDFInt;
  1133.       var NC_NS = "http://home.netscape.com/NC-rdf#";
  1134.       var rSource = RDF.GetResource(aURL);
  1135.       var nameArc = RDF.GetResource(NC_NS+"Name");
  1136.       var urlArc = RDF.GetResource(NC_NS+"URL");
  1137.       var visitArc = RDF.GetResource(NC_NS+"VisitCount");
  1138.       var rName     = HISTDS.GetTarget(rSource, visitArc, true);
  1139.       var visits  = rName ? rName.QueryInterface(kRDFINTIID).Value : -1;
  1140.       return visits;
  1141.     }
  1142.     return -1;
  1143.   },
  1144.   //Functions used to query the bookmarkArray
  1145.   getBookmarkById: function(id){
  1146.     var i;
  1147.     for (i=0; i < this.bookmarkArray.length; i++)
  1148.     if (this.bookmarkArray[i].id == id)
  1149.       return this.bookmarkArray[i];
  1150.     return false;
  1151.   },
  1152.   getBookmarksByLabel: function(label) {
  1153.     var i, j;
  1154.     var ret = new Array();
  1155.     for (i=0; i < this.bookmarkArray.length; i++)
  1156.       for (j=0; j < this.bookmarkArray[i].labels.length; j++)
  1157.         if (this.bookmarkArray[i].labels[j] == label)
  1158.           ret.push(this.bookmarkArray[i]);
  1159.     return ret;
  1160.   },
  1161.   getLabels: function() {
  1162.     var i, j;
  1163.     var ret = new Array();
  1164.     var source=this.bookmarkArray;
  1165.     for (i=0; i < this.bookmarkArray.length; i++) {
  1166.       for (j=0; j < this.bookmarkArray[i].labels.length; j++)
  1167.         if (!this.hasLabel(ret,this.bookmarkArray[i].labels[j]))
  1168.           ret.push(this.bookmarkArray[i].labels[j]);
  1169.     }
  1170.     if (this.sortBy=="title" || true){
  1171.       //Sort labels alphabetically
  1172.       ret.sort(function (x, y){
  1173.         if (x.toString().toLowerCase() < y.toString().toLowerCase())
  1174.           return -1;
  1175.         else if (x.toString().toLowerCase() > y.toString().toLowerCase())
  1176.           return 1;
  1177.         return 0;
  1178.       });
  1179.     }
  1180.     return ret;
  1181.   },
  1182.   hasLabel: function(ret, label) {
  1183.     for (var i=0;i < ret.length; i++){
  1184.       if (ret[i] == label)
  1185.         return true;
  1186.     }
  1187.     return false;
  1188.   },
  1189.   isBookmarked: function(url) {
  1190.     var i;
  1191.     for (i=0; i < this.bookmarkArray.length; i++)
  1192.       if (this.bookmarkArray[i].url == url)
  1193.         return i;
  1194.  
  1195.     return false;
  1196.   },
  1197.   getUnlabeled: function(){
  1198.     var ret=new Array();
  1199.     for (var i=0; i < this.bookmarkArray.length; i++)
  1200.       if (this.bookmarkArray[i].labels.length==0)
  1201.         ret.push(this.bookmarkArray[i]);
  1202.  
  1203.     return ret;
  1204.   },
  1205.   isInToolbar: function(bkmk){
  1206.     if (this.toolbarFolder.length==0)
  1207.       return false;
  1208.     if (bkmk.labels.indexOf(this.toolbarFolder)>-1)
  1209.       return true;
  1210.     for (var i=0;i<bkmk.labels.length;i++){
  1211.       if (bkmk.labels[i]+this.nestedChar==
  1212.           this.toolbarFolder.substring(0,bkmk.labels[i].length+this.nestedChar.length))
  1213.         return true;
  1214.     }
  1215.     return false;
  1216.   },
  1217.   /*
  1218.    * Util function used to alert/prompt the user, check if text is selected, etc.
  1219.    */
  1220.   getBrowserWindow: function(){
  1221.     var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].
  1222.         getService();
  1223.     var windowManagerInterface = windowManager.QueryInterface(
  1224.         Components.interfaces.nsIWindowMediator);
  1225.     var topWindowOfType = windowManagerInterface.getMostRecentWindow(
  1226.         "navigator:browser" );
  1227.     return topWindowOfType;
  1228.   },
  1229.   alertUser: function(msg){
  1230.     var browser=this.getBrowserWindow();
  1231.     browser.alert(msg);
  1232.   },
  1233.   //Required
  1234.   QueryInterface: function(iid) {
  1235.     if (!iid.equals(Components.interfaces.nsISupports) &&
  1236.       !iid.equals(GMARKS_IID))
  1237.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1238.     return this;
  1239.   }
  1240. };
  1241. function debug(msg,force){
  1242.   if (force){
  1243.     dump(msg);
  1244.   }
  1245.   else{
  1246.     //dump(msg);
  1247.   }
  1248. }
  1249. function imageURIChecker(idx,type, url)
  1250. {
  1251.   this.idx  = idx;
  1252.   this.type = type;
  1253.   this.url  = url;
  1254. }
  1255.  
  1256. imageURIChecker.prototype =
  1257. {
  1258.   onStartRequest: function(request, context) {
  1259.     /* Check for redirect */
  1260.     context = context.QueryInterface(Components.interfaces.nsIURI);
  1261.     var startUrl = context.spec.substring(context.spec.indexOf(context.scheme)+context.scheme.length+3);
  1262.     var ioservice = Components.classes["@mozilla.org/network/io-service;1"]
  1263.                            .getService(Components.interfaces.nsIIOService);
  1264.     var endUri = ioservice.newURI(request.name, null, null);
  1265.     var endUrl = request.name.substring(request.name.indexOf(endUri.scheme)+endUri.scheme.length+3)
  1266.     if (endUri.path.indexOf(".ico")<0){
  1267.       const NS_BINDING_ABORTED = 0x804b0002;
  1268.       request.cancel(NS_BINDING_ABORTED);
  1269.       //throw "GMarks URI Checker: No favicon exists";
  1270.     }
  1271.   },
  1272.   onStopRequest: function(request, context, status)
  1273.   {
  1274.     if (status==0){
  1275.       if (this.type==0){
  1276.         var idx=this.idx;
  1277.         while(
  1278.           idx<gGMarks.bookmarkArray.length &&
  1279.           this.url!=gGMarks.bookmarkArray[idx].url){
  1280.           idx++;
  1281.         }
  1282.         if (idx<gGMarks.bookmarkArray.length && idx>=0){
  1283.           gGMarks.bookmarkArray[idx].image=request.name;
  1284.           if (gGMarks.isInToolbar(gGMarks.bookmarkArray[idx]))
  1285.             gGMarks.doCommand("updateToolbarImage",gGMarks.bookmarkArray[idx].id+"\n"+
  1286.                 gGMarks.bookmarkArray[idx].image);
  1287.         }
  1288.       }
  1289.       else{
  1290.         if (gGMarks.searchArray!=null && gGMarks.searchArray.length>this.idx){
  1291.           gGMarks.searchArray[this.idx].image=request.name;
  1292.         }
  1293.       }
  1294.     }
  1295.     else{
  1296.       if (this.type==0){
  1297.         if (this.idx<gGMarks.bookmarkArray.length && this.idx>=0)
  1298.           gGMarks.bookmarkArray[this.idx].image=null;
  1299.         else
  1300.           Components.utils.reportError("Error with image uri checker: "+this.idx);
  1301.       }
  1302.       else{
  1303.         gGMarks.searchArray[this.idx].image=null;
  1304.       }
  1305.     }
  1306.   }
  1307. }
  1308. var nsGMarksServiceModule = {
  1309.   registerSelf: function(compMgr, fileSpec, location, type) {
  1310.     compMgr =
  1311.     compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1312.     compMgr.registerFactoryLocation(GMARKS_CID,
  1313.                     "GMarks",
  1314.                     GMARKS_CONTRACTID,
  1315.                     fileSpec,
  1316.                     location,
  1317.                     type);
  1318.   },
  1319.   unregisterSelf: function(aCompMgr, aLocation, aType)
  1320.   {
  1321.     aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1322.     aCompMgr.unregisterFactoryLocation(GMARKS_CID, aLocation);
  1323.   },
  1324.   getClassObject: function(compMgr, cid, iid) {
  1325.     if (!cid.equals(GMARKS_CID))
  1326.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1327.     if (!iid.equals(Components.interfaces.nsIFactory))
  1328.       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1329.     return nsGMarksServiceFactory;
  1330.   },
  1331.   canUnload: function(compMgr) { return true; }
  1332. };
  1333. var nsGMarksServiceFactory = {
  1334.   createInstance: function (aOuter, aIID)
  1335.   {
  1336.   if (aOuter != null)
  1337.     throw Components.results.NS_ERROR_NO_AGGREGATION;
  1338.   if (gGMarks == null){
  1339.     gGMarks = new nsGMarksService();
  1340.   }
  1341.   return gGMarks.QueryInterface(aIID);
  1342.   }
  1343. };
  1344. function NSGetModule(comMgr, fileSpec) { return nsGMarksServiceModule; }
  1345.